
package com.example.videotrim.utils;

import android.graphics.Bitmap;
import android.os.Handler;
import android.util.Log;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentHashMap;

/*
 * referenced to : http://code.google.com/p/android-imagedownloader/source/browse/trunk/src/com/example/android/imagedownloader/ImageDownloader.java
 */
public class BitmapCache {
    private static final String TAG = "BitmapCache";

    private static final int HARD_CACHE_CAPACITY = 4;

    private static final int DELAY_BEFORE_PURGE = 10 * 1000;

    private final HashMap<String, Bitmap> mHardBitmapCache = new LinkedHashMap<String, Bitmap>(
            HARD_CACHE_CAPACITY / 2, 0.75f, true) {
        protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
            if (size() > HARD_CACHE_CAPACITY) {
                Log.v(TAG, "removeEldestEntry --> move cache from hard to soft, key:"
                        + eldest.getKey() + ", bitmap:" + eldest.getValue());
                mSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
                return true;
            } else
                return false;
        }
    };

    private final ConcurrentHashMap<String, SoftReference<Bitmap>> mSoftBitmapCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>(
            HARD_CACHE_CAPACITY / 2);

    private final Handler purgeHandler = new Handler();

    private final Runnable purger = new Runnable() {
        public void run() {
            Log.v(TAG, "run in purger --> call chearCache");
            clearCache();
        }
    };

    public void addBitmapToCache(String key, Bitmap bitmap) {
        if (bitmap != null) {
            synchronized (mHardBitmapCache) {
                Log.v(TAG, "addBitmapToCache --> key:" + key + ", bitmap:" + bitmap);
                mHardBitmapCache.put(key, bitmap);
            }
        }
    }

    public Bitmap getBitmapFromCache(String key) {
        // first try the hard reference cache
        synchronized (mHardBitmapCache) {
            final Bitmap bitmap = mHardBitmapCache.get(key);
            if (bitmap != null) {
                // bitmap found in hard reference cache
                // move element to first position, so that it is remove last
                mHardBitmapCache.remove(key);
                mHardBitmapCache.put(key, bitmap);
                Log.v(TAG, "getBitmapFromCache --> hit on hard reference");
                return bitmap;
            }
        }

        // then try the soft reference cache
        SoftReference<Bitmap> bitmapReference = mSoftBitmapCache.get(key);
        if (bitmapReference != null) {
            final Bitmap bitmap = bitmapReference.get();
            if (bitmap != null) {
                Log.v(TAG, "getBitmapFromCache --> hit on soft reference");
                return bitmap;
            } else {
                mSoftBitmapCache.remove(key);
            }
        }

        Log.v(TAG, "getBitmapFromCache --> null");
        return null;
    }

    public boolean removeBitmapFromCache(String key) {
        Bitmap bitmap = null;
        SoftReference<Bitmap> bitmapReference = null;

        bitmap = mHardBitmapCache.remove(key);
        if (bitmap != null) {
            Log.v(TAG, "removeBitmapFromCache --> removed from hard cache, key:" + key);
            return true;
        }

        bitmapReference = mSoftBitmapCache.remove(key);
        if (bitmapReference != null) {
            Log.v(TAG, "removeBitmapFromCache --> removed from soft cache, key:" + key);
            return true;
        }

        Log.v(TAG, "removeBitmapFromCache --> bitmap not exist, key:" + key);
        return false;
    }

    public void clearCache() {
        Log.v(TAG, "clearCache");
        mHardBitmapCache.clear();
        mSoftBitmapCache.clear();
    }

    public void resetPurgeTimer() {
        Log.v(TAG, "resetPurgeTimer");
        purgeHandler.removeCallbacks(purger);
        purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE);
    }
}
